﻿using Autofac.Extensions.DependencyInjection;
using Autofac;
using AutoMapper;
using EIP.Common.Quartz;
using EIP.Common.Restful.Middlewares;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System;
using EIP.Common.Entities.Dtos;
using EIP.Common.Restful.Filter;
using EIP.Common.Restful.Jwt;
using EIP.Common.Restful.Provider;
using Microsoft.AspNetCore.Http;
using System.IO;
using Microsoft.Extensions.Hosting;
using System.Linq;
using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using EIP.System.Models.Dtos.Config;
using EIP.System.Models.Dtos.Identity;
using EIP.System.Models.Dtos.Permission;
using EIP.System.Models.Entities;
using Microsoft.Extensions.DependencyModel;
using System.Text.Encodings.Web;
using EIP.Common.Restful.Converter;
using System.Threading.Tasks;
using EIP.Common.Core;

namespace EIP
{
    /// <summary>
    /// 
    /// </summary>
    public class Program
    {
        static bool _isDevelopment;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        public static async Task Main(string[] args)
        {

            var builder = WebApplication.CreateBuilder(args);

            builder.Services.AddControllers(options =>
            {
                options.Filters.Add<ExceptionFilter>();
                options.Filters.Add<ResultFilter>();
                options.Filters.Add<ModelStateFilter>();
                options.Filters.Add<ActionFilter>();
                options.ModelMetadataDetailsProviders.Add(new RequiredBindingMetadataProvider());
            }).AddJsonOptions(options =>
           {
               //options.SerializerSettings.ContractResolver = new DefaultContractResolver();
               //options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";

               //设置时间格式
               options.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss"));
               //设置bool获取格式
               options.JsonSerializerOptions.Converters.Add(new BoolJsonConverter());
               //不使用驼峰样式的key
               options.JsonSerializerOptions.PropertyNamingPolicy = null;
               //不使用驼峰样式的key
               options.JsonSerializerOptions.DictionaryKeyPolicy = null;
               //获取或设置要在转义字符串时使用的编码器
               options.JsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
           });
            builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            #region Swagger基础配置
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc(builder.Configuration["Swagger:Version"], new OpenApiInfo
                {
                    Version = builder.Configuration["Swagger:Version"],
                    Title = builder.Configuration["Swagger:Title"],
                    Description = builder.Configuration["Swagger:Description"],
                    // TermsOfService = new Uri(builder.Configuration["Swagger:TermsOfService"]),
                    Contact = new OpenApiContact
                    {
                        Name = builder.Configuration["Swagger:Contact:Name"],
                        Email = builder.Configuration["Swagger:Contact:Email"],
                        // Url = new Uri(builder.Configuration["Swagger:Contact:Url"])
                    }
                });

                // 添加Bearer认证  
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    Scheme = "Bearer"
                });

                // 为API添加Bearer认证需求  
                c.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            },
                        },
                        new List<string>()
                    }
                });

                var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));

            });
            #endregion

            #region 跨域
            builder.Services.AddCors(options => options.AddPolicy("EIPCors", p => p.WithOrigins(builder.Configuration["Cors:Origins"]).AllowAnyMethod().AllowAnyHeader()));
            #endregion

            #region Jwt
            //获取配置文件
            builder.Services.Configure<JwtConfiguration>(jwtConfig =>
            {
                jwtConfig.Issuer = builder.Configuration["Jwt:Issuer"];
                jwtConfig.Secret = builder.Configuration["Jwt:Secret"];
            });

            // JwtBearer配置
            builder.Services
            .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    if (_isDevelopment)
                        options.RequireHttpsMetadata = false;
                    options.TokenValidationParameters = new TokenValidationParameters()
                    {
                        ValidateIssuer = true, //是否验证Issuer
                        ValidIssuer = builder.Configuration["Jwt:Issuer"], //发行人Issuer
                        ValidateAudience = false, //是否验证Audience
                                                  // ValidAudience = builder.Configuration["Jwt:Audience"], //订阅人Audience
                        ValidateIssuerSigningKey = true, //是否验证SecurityKey
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"])), //SecurityKey
                        ValidateLifetime = true, //是否验证失效时间
                        ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值，解决服务器端时间不同步问题（秒）
                        RequireExpirationTime = true,
                    };
                });
            #endregion

            #region 注册Mapper
            builder.Services.AddAutoMapper(options => options.AddProfile<AutoMapperProfile>());
            #endregion

            #region  EIP基础配置
            builder.Services.Configure<EIPConfig>(builder.Configuration.GetSection("EIP"));
            #endregion

            #region Autofac注入
            builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
            builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
            {
                var assemblies = GetAllAssemblies();
                builder.RegisterAssemblyTypes(assemblies.ToArray()).Where(t => t.Name.EndsWith("Logic")).AsImplementedInterfaces();
                builder.RegisterAssemblyTypes(assemblies.ToArray()).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces();
            });
            #endregion

            var app = builder.Build();

            ServiceLocator.ServiceProvider = app.Services;

            if (app.Environment.IsDevelopment())
            {
                _isDevelopment = true;
                app.UseDeveloperExceptionPage();

                #region Swagger
                app.UseSwagger();
                app.UseSwaggerUI(c =>
                {
                    c.SwaggerEndpoint("/swagger/v1/swagger.json", builder.Configuration["Swagger:Description"]);
                    // 可以在这里配置Swagger UI的其他选项 
                });
                #endregion
            }

            app.UseCors("EIPCors");//注册中间件

            app.UseAuthentication();
            app.UseAuthorization();
            app.MapControllers();

            #region 错误中间件
            app.UseErrorHandlingMiddleware();
            #endregion

            #region 请求中间件
            app.UseRequestProviderMiddleware();
            #endregion

            #region 作业
            await StdSchedulerManager.Init();
            await StdSchedulerManager.Start();
            #endregion

            app.Run();
        }

        /// <summary>
        /// 获取项目程序集，排除所有的系统程序集(Microsoft.***、System.***等)、Nuget下载包
        /// </summary>
        /// <returns></returns>
        static IList<Assembly> GetAllAssemblies()
        {
            var list = new List<Assembly>();
            var libs = DependencyContext.Default.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package" && lib.Name.StartsWith("EIP"));//排除所有的系统程序集、Nuget下载包
            foreach (var lib in libs)
            {
                var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                list.Add(assembly);
            }
            return list;
        }

        /// <summary>
        /// AutoMapper Profile
        /// </summary>
        public class AutoMapperProfile : Profile
        {
            /// <summary>
            /// Mapper注册
            /// </summary>
            public AutoMapperProfile()
            {
                CreateMap<SystemDictionary, SystemDictionaryEditOutput>();
                CreateMap<SystemUserInfo, SystemUserOutput>();
                CreateMap<SystemUserInfo, SystemUserSaveInput>();
                CreateMap<SystemUserSaveInput, SystemUserInfo>();
                CreateMap<SystemUserOutput, SystemUserDetailOutput>();
                CreateMap<SystemMenu, SystemMenuEditOutput>();
                CreateMap<SystemMenuButton, SystemMenuButtonOutput>();
                CreateMap<SystemMenuButton, SystemMenuButtonSaveInput>();
                CreateMap<SystemOrganization, SystemOrganizationOutput>();
                CreateMap<SystemRole, SystemRoleOutput>();
                CreateMap<SystemPost, SystemPostOutput>();
                CreateMap<SystemGroup, SystemGroupOutput>();
                CreateMap<SystemDistrict, SystemDistrictGetByIdOutput>();
            }
        }
    }
}
